import {
    ChangeDetectorRef,
    Component,
    ElementRef,
    forwardRef,
    HostListener,
    Input,
    OnDestroy,
    OnInit,
    ViewChild
} from '@angular/core';
import {OlFeature, OlLayer, OlMap, OlVectorSource} from '../base-map/entity/ol';
import {BaseMapComponent} from '../base-map/base-map/base-map.component';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import WktFormat from 'ol/format/WKT';
import {timer} from 'rxjs';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import GeometryType from 'ol/geom/GeometryType';
import {Fill, Icon, Stroke, Style} from 'ol/style';
import {Draw} from 'ol/interaction';
import Geometry from 'ol/geom/Geometry';
import Modify from 'ol/interaction/Modify';
import Feature from 'ol/Feature';
import Collection from 'ol/Collection';

@Component({
    selector: 'locate-map',
    templateUrl: './locate-map.component.html',
    styleUrls: ['./locate-map.component.less'],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => LocateMapComponent),
            multi: true
        }
    ]
})
export class LocateMapComponent implements OnInit, ControlValueAccessor, OnDestroy {

    @Input() projCode = 'EPSG:4326';

    @Input() locateGeomType: GeometryType = GeometryType.POLYGON;
    @Input() showLayerChange = false;
    @Input() showMapZoom = false;
    @ViewChild(BaseMapComponent, {static: true})
    baseMapComponent: BaseMapComponent;
    map: OlMap;
    _layer: OlLayer;
    _source: OlVectorSource;
    changeFn = undefined;
    disabled = false;
    drawFeature: OlFeature = null;
    wktFormat = new WktFormat();
    drawInteraction: Draw = null;
    modifyInteraction: Modify = null;
    showDraw = true;
    showClear = false;
    showReDraw = false;
    showReset = false;
    showSave = false;
    showModify = false;

    constructor(private element: ElementRef,
                private cd: ChangeDetectorRef) {
    }

    private _wkt: string;

    get wkt(): string {
        return this._wkt;
    }

    @Input()
    set wkt(value: string) {
        this._wkt = value;
        this.addWkt(value);
    }

    ngOnInit() {
        this._source = new VectorSource();
        this._layer = new VectorLayer({
            source: this._source,
            style: new Style({
                fill: new Fill({
                    color: 'rgba(150,201,232,0.2)',
                }),
                stroke: new Stroke({
                    color: '#0092d9',
                    width: 2,
                }),
                image: new Icon({
                    opacity: 1,
                    crossOrigin: 'anonymous',
                    src: './point.png'
                })
            })
        });
        this.addWkt(this._wkt);

        document.onfullscreenchange = () => {
            timer(200).subscribe(v => {
                if (this._source.getFeatures().length > 0) {
                    const geom = this._source.getFeatures()[0].getGeometry().clone();
                    const extent = geom.getExtent();
                    this.map.getView().fit(extent, {
                        padding: [50, 50, 50, 50]
                    });
                }
            });
        };
    }

    ngOnDestroy(): void {
        this.removeInteractions();
        if (this.map && this._layer) {
            this.map.removeLayer(this._layer);
        }
        document.onfullscreenchange = null;
    }

    baseMapInitFinish() {
        this.map = this.baseMapComponent.map;
        this.map.addLayer(this._layer);
    }

    registerOnChange(fn: any): void {
        this.changeFn = fn;
    }

    registerOnTouched(fn: any): void {
    }

    setDisabledState(isDisabled: boolean): void {
        this.disabled = isDisabled;
    }

    writeValue(_value: any): void {
        if (!_value) {
            return;
        }
        this.wkt = _value;
        if (_value) {
            this.showDraw = false;
            this.showClear = true;
            this.showReDraw = true;
            this.showReset = false;
            this.showSave = false;
            this.showModify = true;
        } else {
            this.showDraw = true;
        }

    }

    draw() {
        this.showDraw = false;
        this.showClear = true;
        this.showReDraw = true;
        this.showReset = !!this.wkt;
        this.showSave = false;
        this.showModify = false;


        let geometryType = this.locateGeomType;
        if (!geometryType) {
            geometryType = GeometryType.POLYGON;
        }
        this._source.clear();
        this.addDrawInteraction(geometryType);
    }

    reDraw() {
        let geometryType = this.locateGeomType;
        if (!geometryType) {
            geometryType = GeometryType.POLYGON;
        }
        this._source.clear();
        this.addDrawInteraction(geometryType);
    }

    modify() {
        this.removeInteractions();
        if (this._source.getFeatures().length === 0) {
            this.reDraw();
        } else {
            this.modifyInteraction = new Modify({
                features: new Collection<Feature<Geometry>>(this._source.getFeatures())
            });
            this.map.addInteraction(this.modifyInteraction);

            this.showReset = !!this.wkt;
            this.showSave = true;
            this.showModify = false;
        }
    }

    reset() {
        this.removeInteractions();
        this.wkt = this._wkt;


        this.showDraw = false;
        this.showClear = true;
        this.showReDraw = true;
        this.showReset = false;
        this.showSave = false;
        this.showModify = true;
    }

    addDrawInteraction(geometryType: GeometryType) {
        this.removeInteractions();
        this.drawInteraction = new Draw({
            source: this._source,
            type: geometryType
        });
        this.drawInteraction.on('drawend', res => {
            this.drawFeature = res.feature;
            this.removeInteractions();

            this.showReset = !!this.wkt;
            this.showSave = true;
            this.showModify = true;
            this.cd.markForCheck();
        });
        this.map.addInteraction(this.drawInteraction);
    }

    removeInteractions() {
        if (this.drawInteraction) {
            this.map.removeInteraction(this.drawInteraction);
            this.drawInteraction = null;
        }
        if (this.modifyInteraction) {
            this.map.removeInteraction(this.modifyInteraction);
            this.modifyInteraction = null;
        }
        // if(this.drawFeature && this._source){
        //     this._source.removeFeature(this.drawFeature);
        //     this.drawFeature = null;
        // }
    }

    clear() {
        this.removeInteractions();
        this.wkt = null;

        this.showDraw = true;
        this.showClear = false;
        this.showReDraw = false;
        this.showReset = false;
        this.showSave = false;
        this.showModify = false;
    }

    save() {
        let geom;
        if (this.drawFeature) {
            geom = this.drawFeature.getGeometry();
            this.drawFeature = null;
        } else if (this.modifyInteraction) {
            geom = this._source.getFeatures()[0].getGeometry().clone();
        }
        if (!geom) {
            return;
        }
        geom.transform(this.map.getView().getProjection(), this.projCode);
        this.wkt = this.wktFormat.writeGeometry(geom);
        this.removeInteractions();


        this.showReset = false;
        this.showSave = false;
        this.showModify = true;
    }

    showPoint() {
        return this.locateGeomType === GeometryType.POINT;
    }

    showLine() {
        return this.locateGeomType === GeometryType.LINE_STRING;
    }

    showPolygon() {
        return this.locateGeomType === GeometryType.POLYGON;
    }

    fullScreen() {
        this.element.nativeElement.requestFullscreen().then(v => {
            this.baseMapComponent.updateSize();
        });
    }

    exitFullScreen() {
        document.exitFullscreen();
    }

    isFull() {
        return !!document.fullscreenElement;
    }

    private addWkt(wkt: string) {
        if (this._layer) {
            const source: VectorSource = this._layer.getSource() as VectorSource;

            source.clear();
            if (!wkt) {
                return;
            }
            const geometry = this.wktFormat.readGeometry(wkt);

            // 将数据转换到地图上的坐标系
            geometry.transform(this.projCode, this.map.getView().getProjection());

            const feature = new OlFeature(geometry);
            source.addFeature(feature);
            setTimeout(() => {
                const extent = geometry.getExtent();
                this.map.getView().fit(extent, {
                    padding: [50, 50, 50, 50]
                });
            }, 100);


            if (this.changeFn) {
                this.changeFn(wkt);
            }
        }
    }
}
